package com.weilele.mvvm.base.livedata

import android.os.Looper
import android.widget.Toast
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.weilele.mvvm.utils.activity.toast
import com.weilele.mvvm.utils.printStackTrace

/**
 * 是否是主线程
 */
val isMainThread: Boolean
    get() = Looper.getMainLooper() === Looper.myLooper()

class StatusData<T> {
    companion object {
        const val Running = 1
        const val Success = 2
        const val Error = 3
    }

    /**
     * 状态
     */
    @LiveDataStatus
    private var _status: Int = Running

    @LiveDataStatus
    val status: Int
        @LiveDataStatus
        get() = _status

    /**
     * 数据
     */
    private var _data: T? = null
    val data: T?
        get() = _data

    /**
     * code
     */
    private var _code: Int? = null
    val code: Int?
        get() = _code

    /**
     * 消息
     */
    private var _message: String? = null
    val message: String?
        get() = _message

    /**
     * 赋值
     */
    fun setValue(@LiveDataStatus status: Int, data: T?, code: Int?, message: String?) {
        this._status = status
        this._data = data
        this._code = code
        this._message = message
    }

    /**
     *成功
     */
    fun success(data: T?, code: Int? = null, message: String? = null) {
        setValue(Success, data, code ?: _code, message ?: _message)
    }

    /**
     * 运行
     */
    fun running(data: T? = null, code: Int? = null, message: String? = null) {
        setValue(Running, data ?: _data, code ?: _code, message ?: _message)
    }

    /**
     * 错误
     */
    fun error(message: String?, data: T? = null, code: Int? = null) {
        setValue(Error, data ?: _data, code ?: _code, message)
    }
}

/**
 * 获取非空值
 */
val <T> LiveData<StatusData<T>>.nonValue: StatusData<T>
    get() = this.value ?: StatusData()

/**
 * 获取data
 */
val <T> LiveData<StatusData<T>>.data: T?
    get() = this.value?.data

/**
 * 获取code
 */
val <T> LiveData<StatusData<T>>.code: Int?
    get() = this.value?.code

/**
 * 获取message
 */
val <T> LiveData<StatusData<T>>.message: String?
    get() = this.value?.message

/**
 * 获取status
 */
val <T> LiveData<StatusData<T>>.status: Int?
    @LiveDataStatus
    get() = this.value?.status

/**
 * 是否是运行状态
 */
val <T> LiveData<StatusData<T>>.isRunning: Boolean
    get() = status == StatusData.Running

/**
 * 是否是成功状态
 */
val <T> LiveData<StatusData<T>>.isSuccess: Boolean
    get() = status == StatusData.Success

/**
 * 是否是错误状态
 */
val <T> LiveData<StatusData<T>>.isError: Boolean
    get() = status == StatusData.Error

/**
 * 安全赋值
 */
fun <T> MutableLiveData<T>.safeSetValue(data: T?) {
    if (isMainThread) {
        value = data
    } else {
        postValue(data)
    }
}


/**
 * 赋值
 */
fun <T> MutableLiveData<StatusData<T>>.setStatusData(
    @LiveDataStatus status: Int, data: T?, code: Int?, message: String?
) {
    val oldValue = nonValue
    oldValue.setValue(status, data, code, message)
    safeSetValue(oldValue)
}

/**
 * 成功状态
 */
fun <T> MutableLiveData<StatusData<T>>.success(
    data: T?,
    code: Int? = null,
    message: String? = null
) {
    val oldValue = nonValue
    oldValue.success(data, code, message)
    safeSetValue(oldValue)
}

/**
 * 失败状态
 */
fun <T> MutableLiveData<StatusData<T>>.error(
    message: String?, data: T? = null, code: Int? = null
) {
    val oldValue = nonValue
    oldValue.error(message, data, code)
    safeSetValue(oldValue)
}

/**
 * 运行状态
 */
fun <T> MutableLiveData<StatusData<T>>.running(
    data: T? = null,
    code: Int? = null,
    message: String? = null
) {
    val oldValue = nonValue
    oldValue.running(data, code, message)
    safeSetValue(oldValue)
}


/**
 * 带有状态的运行 livedata，一般在子线程使用
 */
inline fun <T> MutableLiveData<StatusData<T>>.runWithStatus(
    isToastError: Boolean = true/*是否toast出错误*/,
    noinline errorCall: ((Throwable) -> T?)? = null,
    call: () -> T
) {
    try {
        this.running()
        this.success(call.invoke())
    } catch (e: Throwable) {
        printStackTrace { e }
        val message = e.message
            ?: "runWithStatus result Error"
        this.error(message)
        if (isToastError) {
            message.toast(Toast.LENGTH_LONG)
        }
        errorCall?.invoke(e)
    }
}


